<?php
/**
 * 
 * Utility class for XML data and objects representations
 * 
 * @package WKernel
 *
 */
class WK_Markup_Document {
	private $indent = '  ';
	
	private $nsprefix = '';
	private $nsurl    = '';
	private $schema   = '';
	
	private $encoding = 'UTF-8';
	
	private $content;
	
	/**
	 * Set document namespace
	 * @param string $url namespace
	 * @param string $prefix namespace prefix
	 */
	public function setNamespace($url, $prefix){
		$this->nsprefix = $this->ns($prefix);
		$this->nsurl    = $url;
	}
	
	/**
	 * Set document XML schema location
	 * @param $url Schema location
	 */
	public function setSchema($url) {
		$this->schema = $url;
	}
	
	/**
	 * Set document encoding
	 * @param string $encoding
	 */
	public function setEcoding($encoding){
		$this->encoding = $encoding;
	}
	
	/**
	 * Return document content
	 * @param string $name element name
	 * @param array $attrs attributes
	 * @param string $content element content
	 * @param boolean $omit_declaration omit XML declaration or not
	 * @return string
	 */
	public function createRootElement($name, $attrs, $content, $omit_declaration = true){
		$element = $omit_declaration ? '' : $this->getDeclaration() . "\n";
		if(!$omit_declaration) {
			$attrs = array_merge($attrs, array( 
				'xmlns' . ':' . trim($this->nsprefix, ':') => $this->nsurl,
				'xmlns:xsi'          => 'http://www.w3.org/2001/XMLSchema-instance',
				'xsi:schemaLocation' => $this->nsurl . ' ' . $this->schema)
			);
		}
		return $element . $this->createElement($name, $attrs, $content, 0, 1);
	}
	
	public function openRootElement($name, $attrs, $omit_declaration = true){
		$element = $omit_declaration ? '' : $this->getDeclaration() . "\n";
		if(!$omit_declaration) {
			$attrs = array_merge($attrs, array( 
				'xmlns' . ':' . trim($this->nsprefix, ':') => $this->nsurl,
				'xmlns:xsi'          => 'http://www.w3.org/2001/XMLSchema-instance',
				'xsi:schemaLocation' => $this->nsurl . ' ' . $this->schema)
			);
		}
		return $element . $this->openElement($name, $attrs, 0);
	}
	
	/**
	 * Return element content
	 * @param string $name element name
	 * @param array $attrs attributes
	 * @param string $content element content
	 * @param integer $level level of the element 
	 * @param integer $m_indents mask of line brakes before and after element 
	 * 							 (3 - all, 2 - before only, 1 - after only)
	 * @param boolean $iscdata is element value CDATA
	 * @return string
	 */
	public function createElement ($name, $attrs, $content, $level = 0, $m_indents = 3, $iscdata = false, 
								   $autocomplete = true){
		$ns = $this->nsprefix; $content = strval($content);		
		$indent = $this->getIndent($level);
		$xml  = (($m_indents & 2) > 0 ? $indent : '') . '<' . $ns . $name . $this->attrs($attrs);		
		if(!empty($content) || $content == '0' || !$autocomplete) {			
			$xml .= '>' . ($iscdata ? '<![CDATA[' : '') .$content . ($iscdata ? ']]>' : '');		
			$xml .= (($m_indents & 1) > 0 ? $indent : '') . '</' . $ns . $name .'>';
		}
		else
			$xml .= '/>';
		return $xml;
	}
	
	public function openElement ($name, $attrs, $level) {
		return ($level > 0 ? $this->getIndent($level) : '') . '<' . $this->nsprefix . $name . $this->attrs($attrs) . '>';
	}
	
	public function closeElement ($name, $level) {
		return $this->getIndent($level) . '</' . $this->nsprefix . $name . '>';
	}
	
	/**
	 * Return XML declaration
	 */
	protected function getDeclaration(){
		return '<?xml version="1.0" encoding="' . $this->encoding . '"?>';
	}
	
	/**
	 * Return element indentation string for level 
	 * @param integer $level
	 * @return string
	 */
	protected function getIndent ($level) {
		return "\n" . str_repeat($this->indent, $level);
	}
	
	/**
	 * Return name document space prefix 
	 * @param $ns
	 */
	protected function ns ($ns) {		
		if(!empty($ns) && substr($ns, strlen($ns) - 1) != ':')
			return $ns . ':';
		else
			return $ns;
	}	
	
	/**
	 * Represent array of element attributes as string
	 * @param array $attrs
	 * @return string
	 */
	protected function attrs($attrs){
		if(empty($attrs)) return '';
		$xml = '';
		foreach ($attrs as $name => $value){
			$xml .= ' ' . $name . '="' . $value .'"';
		}
		return $xml;
	}
}